﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using pub.Interop;

namespace pub.Controls
{
    class SplitButton : Button
    {
        private const int _splitAreaWidth = 16;
        private static readonly int _borderSize = SystemInformation.Border3DSize.Width * 2;

        private Rectangle _splitArea;
        private ContextMenu _menu;
        private bool _showingMenu;
        private bool _closingUp;

        public SplitButton()
        {
            this.Padding = new Padding(0, 0, _splitArea.Width - 5, 0);
        }

        /*------------------- interface ---------------*/

        [DefaultValue(null)]
        public ContextMenu SplitMenu
        {
            get { return _menu; }
            set { _menu = value; }
        }

        /*-------------------- keyboard --------------------*/

        protected override bool IsInputKey(Keys keyData)
        {
            if (keyData.Equals(Keys.Down))
                return true;

            return base.IsInputKey(keyData);
        }

        protected override void OnKeyDown(KeyEventArgs kevent)
        {
            if (kevent.KeyCode.Equals(Keys.Down))
            {
                ShowMenu();
            }

            base.OnKeyDown(kevent);
        }

        protected override void OnKeyUp(KeyEventArgs kevent)
        {
            if (kevent.KeyCode.Equals(Keys.Apps))
            {
                ShowMenu();
            }

            base.OnKeyUp(kevent);
        }


        /*------------------ mouse -----------------------*/

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (_closingUp)
            {
                _closingUp = false;
                return;
            }

            if (e.Button == MouseButtons.Left && _splitArea.Contains(e.Location))
            {
                ShowMenu();
            }
            else
            {
                base.OnMouseDown(e);
            }
        }

        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            _closingUp = false;
            base.OnMouseUp(mevent);

            if (mevent.Button == MouseButtons.Right && ClientRectangle.Contains(mevent.Location))
            {
                ShowMenu();
            }
        }

        /*---------------------- draw -------------------*/

        protected override void OnPaint(PaintEventArgs pevent)
        {
            base.OnPaint(pevent);

            var g = pevent.Graphics;
            var bounds = ClientRectangle;

            var state = this.AccessibilityObject.State;

            _splitArea = new Rectangle(bounds.Right - _splitAreaWidth, 0,
                _splitAreaWidth, bounds.Height);

            if ((state & AccessibleStates.Pressed) != 0 && !Application.RenderWithVisualStyles)
            {
                g.DrawLine(SystemPens.ButtonShadow, bounds.Right - _splitAreaWidth,
                    _borderSize, bounds.Right - _splitAreaWidth, bounds.Bottom - _borderSize);
            }
            else
            {
                g.DrawLine(SystemPens.ButtonShadow, bounds.Right - _splitAreaWidth - 1,
                    _borderSize, bounds.Right - _splitAreaWidth - 1, bounds.Bottom - _borderSize);
                g.DrawLine(SystemPens.ButtonHighlight, bounds.Right - _splitAreaWidth, _borderSize,
                    bounds.Right - _splitAreaWidth, bounds.Bottom - _borderSize);
            }

            if (_showingMenu)
            {
                if (Application.RenderWithVisualStyles)
                {
//                    g.DrawLine(SystemPens.da, bounds.Right - _splitAreaWidth, _borderSize,
//                    bounds.Right - _splitAreaWidth, bounds.Bottom - _borderSize);
                    var rc = new Rectangle(_splitArea.X - 20, _splitArea.Y,
                        _splitArea.Width + 20, _splitArea.Height);

                    var oldClip = g.Clip;
                    g.Clip = new Region(new Rectangle(rc.X + 19, rc.Y, rc.Width - 19, rc.Height));
                    ButtonRenderer.DrawButton(g, rc, PushButtonState.Pressed);
                    g.Clip = oldClip;

                    //*
                    g.DrawLine(SystemPens.ControlDark, bounds.Right - _splitAreaWidth - 1,
                        _borderSize, bounds.Right - _splitAreaWidth - 1, bounds.Bottom - _borderSize - 1);
                    g.DrawLine(SystemPens.ControlDarkDark, bounds.Right - _splitAreaWidth, _borderSize,
                        bounds.Right - _splitAreaWidth, bounds.Bottom - _borderSize - 1);
                    //*/
                }
                else
                {
                    var rc = new Rectangle(_splitArea.X, _splitArea.Y + 1,
                    _splitArea.Width - 1, _splitArea.Height - 2);
                    ButtonRenderer.DrawButton(g, rc, PushButtonState.Pressed);
                }
            }
            PaintArrow(g, _splitArea);
        }

        private void PaintArrow(Graphics g, Rectangle dropDownRect)
        {
            var middle = new Point(Convert.ToInt32(dropDownRect.Left + dropDownRect.Width / 2),
                Convert.ToInt32(dropDownRect.Top + dropDownRect.Height / 2));

            middle.X += (dropDownRect.Width % 2) - 1;

            var arrow = new[] {
                new Point(middle.X - 2, middle.Y - 1),
                new Point(middle.X + 3, middle.Y - 1),
                new Point(middle.X, middle.Y + 2)
            };

            if (Enabled)
            {
                g.FillPolygon(SystemBrushes.ControlText, arrow);
            }
            else
            {
                g.FillPolygon(SystemBrushes.ButtonShadow, arrow);
            }
        }

        /*------------------------- functions -------------------------*/

        private void ShowMenu()
        {
            var pos = this.PointToScreen(new Point(0, Height));
            //                m_SplitMenu.Show(this, new Point(0, Height));

            _showingMenu = true;
            //
            this.Invalidate();
            Win32.TrackPopupMenu(_menu.Handle, 0, pos.X, pos.Y, 0, this.Handle, IntPtr.Zero);

            _showingMenu = false;

            this.Invalidate();

            var pt = this.PointToClient(Cursor.Position);
            if (Win32.GetAsyncKeyState(Win32.MK_LBUTTON) < 0 && this._splitArea.Contains(pt))
            {
                _closingUp = true;
            }
        }


        /*=====================================================================*/
    }
}